package com.github.baichuan.file.rest.controller;

import com.github.baichuan.file.rest.dto.Base64File;
import com.github.baichuan.utils.SnowFlake;
import com.github.baichuan.web.dto.Result;
import io.minio.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Tag(name = "基于Minio服务文件服务")
@RestController
@RequestMapping("/{bucket:^(?!.*swagger-ui).*$}")
//@RequestMapping("/{bucket}")
@ConditionalOnBean(MinioClient.class)
@Slf4j
public class MinioController {
    @Autowired
    private MinioClient minio;
    @Autowired
    private SnowFlake snowFlake;
    @Autowired
    private Base64.Decoder base64Decoder;
    @Autowired
    private Base64.Encoder base64Encoder;

    @Operation(summary = "上传Base64格式文件")
    @PostMapping("/base64/upload")
    public ResponseEntity upload(@PathVariable("bucket") String bucket, @RequestBody @Validated Base64File file) {
        byte[] bytes = base64Decoder.decode(file.getBase64());

        String fileId = snowFlake.nextBase62Id();
        Map<String, String> meta = new HashMap<>();
        meta.put("file-name", file.getName());

        try(InputStream inputStream = new ByteArrayInputStream(bytes)){
            PutObjectArgs object = PutObjectArgs.builder()
                    .bucket(bucket)
                    .object(fileId)
                    .userMetadata(meta)
                    .stream(inputStream, bytes.length, -1)
                    .contentType(file.getMime())
                    .build();
            minio.putObject(object);
        } catch (Exception e) {
            log.error("保存文件{}:{}发生错误：{}", bucket, fileId, e.getMessage());
            return ResponseEntity.ok(Result.fail("保存文件发生错误"));
        }

        return ResponseEntity.ok(Result.success("文件保存成功", fileId));
    }

    @Operation(summary = "获取Base64格式文件")
    @GetMapping("/base64/{file}")
    public ResponseEntity get(@PathVariable("bucket") String bucket, @PathVariable("file") String file){
        GetObjectArgs objectArgs = GetObjectArgs.builder()
                .bucket(bucket)
                .object(file)
                .build();
        try(GetObjectResponse objectResponse = minio.getObject(objectArgs);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            int length = 0;
            byte[] buf = new byte[1024 * 8];
            while ((length = objectResponse.read(buf)) != -1) {
                outputStream.write(buf, 0, length);
            }

            Base64File base64File = new Base64File();
            base64File.setName(objectResponse.headers().get("x-amz-meta-filename"));
            base64File.setMime(objectResponse.headers().get("Content-Type"));
            base64File.setBase64(base64Encoder.encodeToString(outputStream.toByteArray()));

            return ResponseEntity.ok(base64File);
        } catch (Exception ex){
            log.error("获取文件{}:{}消息：{}", bucket, file, ex.getMessage());
            return ResponseEntity.ok(Result.fail("获取文件发生错误"));
        }
    }

    @Operation(summary = "表单上传文件")
    @PostMapping("/upload")
    public ResponseEntity upload(@PathVariable("bucket") String bucket, @RequestPart("file") MultipartFile multipartFile){
        return ResponseEntity.ok(null);
    }

    @Operation(summary = "删除文件")
    @DeleteMapping("/{file")
    public ResponseEntity delete(@PathVariable("bucket") String bucket, @PathVariable("id") String file) {
        RemoveObjectArgs removeArgs = RemoveObjectArgs.builder().bucket(bucket).object(file).build();
        try{
            minio.removeObject(removeArgs);
        } catch (Exception ex){
            log.error(ex.getMessage());
            return ResponseEntity.ok(Result.fail("文件删除发生错误"));
        }


        return ResponseEntity.ok(Result.success("文件删除成功"));
    }
}
